package com.chuangjiangx.member.basic.web.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chuangjiangx.commons.JacksonUtils;
import com.chuangjiangx.commons.response.GenericResponse;
import com.chuangjiangx.commons.response.Response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

/**
 * Created by zhoufushou on 2017/12/25.
 * 支付码界面websocket推送
 */
@Slf4j
public class MemberCodePayWebSocketHandler  implements WebSocketHandler {

    @Autowired
    private ObjectMapper objectMapper;
    public static final String MEMBER_ID_KEY = "memberId";

    public static final ConcurrentHashMap<Long,WebSocketSession> USER = new ConcurrentHashMap<>(128);

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("websocket连接成功,session:{},",session);
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        log.info("handleMessage,session:{},message:{}",session, JacksonUtils.toJson(objectMapper,message));
        Response response;
        Long memberId = null;
        try{
            MapType mapType = objectMapper.getTypeFactory().constructMapType(HashMap.class, String.class, String.class);
            Map<String,String> map = objectMapper.readValue(message.getPayload().toString(), mapType);
            memberId = Long.valueOf(map.get(MEMBER_ID_KEY));
        }catch (Exception e){
            log.error("webSocket接收json消息解析失败,message:{}",message.getPayload(),e);
        }
        if(memberId == null){
            response =  GenericResponse.failure("","未找到登录信息，请重新登录");
            session.sendMessage(new TextMessage(JSONObject.toJSONString(response)));
            return;
        }
        //设置会员Id
        session.getAttributes().put(MEMBER_ID_KEY,memberId);
        USER.put(memberId,session);
        log.info("websocket连接数:{}",USER.size());
        session.sendMessage(new TextMessage(JSONObject.toJSONString(GenericResponse.success(null))));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("handleTransportError,session:{}，exception:{}" , session,exception.getMessage(),exception);
        releaseSession(session);
    }

    private static void releaseSession(WebSocketSession session) throws IOException {
        if(null != session ){
            if(session.isOpen()){
                session.close();
            }
            Long memberId;
            if(null != (memberId = (Long) session.getAttributes().get(MEMBER_ID_KEY))){
                USER.remove(memberId);
                log.info("websocket连接数:{}",USER.size());
            }
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        log.info("afterConnectionClosed,session:{}，closeStatus:{}" , session,closeStatus.getReason());
        releaseSession(session);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 给用户发送消息
     * @param dataMap 推送内容map
     */
    public static void sendMessageToCustomer(final Map<String, Object> dataMap) throws IOException {
        Long memberId = (Long) dataMap.get(MEMBER_ID_KEY);
        if(null == memberId){
            return;
        }
        //延时创建
        Supplier<TextMessage> messageSupplier = () -> new TextMessage(JSON.toJSONString(dataMap));
        WebSocketSession webSocketSession = USER.get(memberId);
        if(null != webSocketSession){
            if(webSocketSession.isOpen()){
                webSocketSession.sendMessage(messageSupplier.get());
            } else {
                log.warn("向用推送消息时,websocket确已经关闭,memberId:{},session:{}",memberId,webSocketSession);
                releaseSession(webSocketSession);
            }
        }

    }
}